﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "GcmpApiFoundation.h"
#include <functional>
namespace gdmp {
    namespace api {
        namespace traits {
            template <typename U>
            struct has_object_kind
            {
                template <typename T, const char* (T::*)()const = &T::ObjectKind>
                static constexpr std::true_type test(T*);
                static constexpr std::false_type test(...);
                using type = decltype(test(static_cast<U*>(nullptr)));
            };
        }

        // Native转C#对象
        using APIObjectCreator = void* (*)(void*);
        class GCMP_API_FOUNDATION_EXPORT APIObjectCreatorMap
        {
        public:
            APIObjectCreatorMap(const char* type, APIObjectCreator&& creator);
            static APIObjectCreator get(const char* type);
        };

        // C++ API对象构造器
        class Object;
        using ObjectCreator = std::function<gdmp::api::Object* ()>;
        class GCMP_API_FOUNDATION_EXPORT ObjectCreatorMap
        {
        public:
            template<typename T>
            ObjectCreatorMap(T*, ObjectCreator objectCreator, int grade)
            {
                static_assert(traits::has_object_kind<T>::type(), "模板类型T没有方法ObjectKind");
                Register(T::ClassType(), objectCreator, grade);
            }    
            
            template<>
            ObjectCreatorMap(const char* classType, ObjectCreator objectCreator, int grade)
            {
                Register(classType, objectCreator, grade);
            }

            static ObjectCreator get(const char* type);
            template<typename T>
            static ObjectCreator get(const T* object)
            {
                if (nullptr != object)
                {
                    ObjectCreator creator = get(object->ObjectKind());
                    if (nullptr != creator)
                    {
                        return creator;
                    }
                }
                return get(T::ClassType());
            }

        private:
            void Register(const char* type, ObjectCreator objectCreator, int grade);
        };
    }
}

#pragma region 注册API C++类型构造器
//使用类型注册
#define REGISTER_API_CREATOR_GRADE(IMPTYPE, APITYPE, PRIORITY) \
namespace{\
    static gdmp::api::ObjectCreatorMap registerCreator(static_cast<IMPTYPE*>(nullptr), []{return NEW_AS_PTR(APITYPE);},PRIORITY); \
}

#define REGISTER_API_CREATOR(IMPTYPE, APITYPE) \
REGISTER_API_CREATOR_GRADE(IMPTYPE, APITYPE,0)

//使用类型字符串(const char*)
#define REGISTER_API_CREATOR_GRADE_BYNAME(CLASSNAME, APITYPE, PRIORITY) \
namespace{\
    static gdmp::api::ObjectCreatorMap registerCreator(CLASSNAME, []{return NEW_AS_PTR(APITYPE);},PRIORITY); \
}

#define REGISTER_API_CREATOR_BYNAME(CLASSNAME, APITYPE) \
REGISTER_API_CREATOR_GRADE_BYNAME(CLASSNAME, APITYPE,0)

#pragma endregion
